home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-04-04 | 58.1 KB | 2,179 lines |
- Newsgroups: comp.sources.unix
- From: phil@Shiva.COM (Phil Budne)
- Subject: v25i169: finger - Phil's Finger Program, Part06/07
- Sender: unix-sources-moderator@pa.dec.com
- Approved: vixie@pa.dec.com
-
- Submitted-By: phil@Shiva.COM (Phil Budne)
- Posting-Number: Volume 25, Issue 169
- Archive-Name: finger/part06
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 6 (of 7)."
- # Contents: COPYING finger.c fingerd.c getcommand.c
- # Wrapped by budd@bu-it on Fri Jul 6 13:22:06 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f COPYING -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"COPYING\"
- else
- echo shar: Extracting \"COPYING\" \(12042 characters\)
- sed "s/^X//" >COPYING <<'END_OF_COPYING'
- X GNU GENERAL PUBLIC LICENSE
- X Version 1, February 1989
- X
- X Copyright (C) 1989 Free Software Foundation, Inc.
- X 675 Mass Ave, Cambridge, MA 02139, USA
- X Everyone is permitted to copy and distribute verbatim copies
- X of this license document, but changing it is not allowed.
- X
- X Preamble
- X
- X The license agreements of most software companies try to keep users
- Xat the mercy of those companies. By contrast, our General Public
- XLicense is intended to guarantee your freedom to share and change free
- Xsoftware--to make sure the software is free for all its users. The
- XGeneral Public License applies to the Free Software Foundation's
- Xsoftware and to any other program whose authors commit to using it.
- XYou can use it for your programs, too.
- X
- X When we speak of free software, we are referring to freedom, not
- Xprice. Specifically, the General Public License is designed to make
- Xsure that you have the freedom to give away or sell copies of free
- Xsoftware, that you receive source code or can get it if you want it,
- Xthat you can change the software or use pieces of it in new free
- Xprograms; and that you know you can do these things.
- X
- X To protect your rights, we need to make restrictions that forbid
- Xanyone to deny you these rights or to ask you to surrender the rights.
- XThese restrictions translate to certain responsibilities for you if you
- Xdistribute copies of the software, or if you modify it.
- X
- X For example, if you distribute copies of a such a program, whether
- Xgratis or for a fee, you must give the recipients all the rights that
- Xyou have. You must make sure that they, too, receive or can get the
- Xsource code. And you must tell them their rights.
- X
- X We protect your rights with two steps: (1) copyright the software, and
- X(2) offer you this license which gives you legal permission to copy,
- Xdistribute and/or modify the software.
- X
- X Also, for each author's protection and ours, we want to make certain
- Xthat everyone understands that there is no warranty for this free
- Xsoftware. If the software is modified by someone else and passed on, we
- Xwant its recipients to know that what they have is not the original, so
- Xthat any problems introduced by others will not reflect on the original
- Xauthors' reputations.
- X
- X The precise terms and conditions for copying, distribution and
- Xmodification follow.
- X
- X GNU GENERAL PUBLIC LICENSE
- X TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
- X
- X 0. This License Agreement applies to any program or other work which
- Xcontains a notice placed by the copyright holder saying it may be
- Xdistributed under the terms of this General Public License. The
- X"Program", below, refers to any such program or work, and a "work based
- Xon the Program" means either the Program or any work containing the
- XProgram or a portion of it, either verbatim or with modifications. Each
- Xlicensee is addressed as "you".
- X
- X 1. You may copy and distribute verbatim copies of the Program's source
- Xcode as you receive it, in any medium, provided that you conspicuously and
- Xappropriately publish on each copy an appropriate copyright notice and
- Xdisclaimer of warranty; keep intact all the notices that refer to this
- XGeneral Public License and to the absence of any warranty; and give any
- Xother recipients of the Program a copy of this General Public License
- Xalong with the Program. You may charge a fee for the physical act of
- Xtransferring a copy.
- X
- X 2. You may modify your copy or copies of the Program or any portion of
- Xit, and copy and distribute such modifications under the terms of Paragraph
- X1 above, provided that you also do the following:
- X
- X a) cause the modified files to carry prominent notices stating that
- X you changed the files and the date of any change; and
- X
- X b) cause the whole of any work that you distribute or publish, that
- X in whole or in part contains the Program or any part thereof, either
- X with or without modifications, to be licensed at no charge to all
- X third parties under the terms of this General Public License (except
- X that you may choose to grant warranty protection to some or all
- X third parties, at your option).
- X
- X c) If the modified program normally reads commands interactively when
- X run, you must cause it, when started running for such interactive use
- X in the simplest and most usual way, to print or display an
- X announcement including an appropriate copyright notice and a notice
- X that there is no warranty (or else, saying that you provide a
- X warranty) and that users may redistribute the program under these
- X conditions, and telling the user how to view a copy of this General
- X Public License.
- X
- X d) You may charge a fee for the physical act of transferring a
- X copy, and you may at your option offer warranty protection in
- X exchange for a fee.
- X
- XMere aggregation of another independent work with the Program (or its
- Xderivative) on a volume of a storage or distribution medium does not bring
- Xthe other work under the scope of these terms.
- X
- X 3. You may copy and distribute the Program (or a portion or derivative of
- Xit, under Paragraph 2) in object code or executable form under the terms of
- XParagraphs 1 and 2 above provided that you also do one of the following:
- X
- X a) accompany it with the complete corresponding machine-readable
- X source code, which must be distributed under the terms of
- X Paragraphs 1 and 2 above; or,
- X
- X b) accompany it with a written offer, valid for at least three
- X years, to give any third party free (except for a nominal charge
- X for the cost of distribution) a complete machine-readable copy of the
- X corresponding source code, to be distributed under the terms of
- X Paragraphs 1 and 2 above; or,
- X
- X c) accompany it with the information you received as to where the
- X corresponding source code may be obtained. (This alternative is
- X allowed only for noncommercial distribution and only if you
- X received the program in object code or executable form alone.)
- X
- XSource code for a work means the preferred form of the work for making
- Xmodifications to it. For an executable file, complete source code means
- Xall the source code for all modules it contains; but, as a special
- Xexception, it need not include source code for modules which are standard
- Xlibraries that accompany the operating system on which the executable
- Xfile runs, or for standard header files or definitions files that
- Xaccompany that operating system.
- X
- X 4. You may not copy, modify, sublicense, distribute or transfer the
- XProgram except as expressly provided under this General Public License.
- XAny attempt otherwise to copy, modify, sublicense, distribute or transfer
- Xthe Program is void, and will automatically terminate your rights to use
- Xthe Program under this License. However, parties who have received
- Xcopies, or rights to use copies, from you under this General Public
- XLicense will not have their licenses terminated so long as such parties
- Xremain in full compliance.
- X
- X 5. By copying, distributing or modifying the Program (or any work based
- Xon the Program) you indicate your acceptance of this license to do so,
- Xand all its terms and conditions.
- X
- X 6. Each time you redistribute the Program (or any work based on the
- XProgram), the recipient automatically receives a license from the original
- Xlicensor to copy, distribute or modify the Program subject to these
- Xterms and conditions. You may not impose any further restrictions on the
- Xrecipients' exercise of the rights granted herein.
- X
- X 7. The Free Software Foundation may publish revised and/or new versions
- Xof the General Public License from time to time. Such new versions will
- Xbe similar in spirit to the present version, but may differ in detail to
- Xaddress new problems or concerns.
- X
- XEach version is given a distinguishing version number. If the Program
- Xspecifies a version number of the license which applies to it and "any
- Xlater version", you have the option of following the terms and conditions
- Xeither of that version or of any later version published by the Free
- XSoftware Foundation. If the Program does not specify a version number of
- Xthe license, you may choose any version ever published by the Free Software
- XFoundation.
- X
- X 8. If you wish to incorporate parts of the Program into other free
- Xprograms whose distribution conditions are different, write to the author
- Xto ask for permission. For software which is copyrighted by the Free
- XSoftware Foundation, write to the Free Software Foundation; we sometimes
- Xmake exceptions for this. Our decision will be guided by the two goals
- Xof preserving the free status of all derivatives of our free software and
- Xof promoting the sharing and reuse of software generally.
- X
- X NO WARRANTY
- X
- X 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
- XFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
- XOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
- XPROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
- XOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- XMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
- XTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
- XPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
- XREPAIR OR CORRECTION.
- X
- X 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
- XWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
- XREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
- XINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
- XOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
- XTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
- XYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
- XPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
- XPOSSIBILITY OF SUCH DAMAGES.
- X
- X END OF TERMS AND CONDITIONS
- X
- X Appendix: How to Apply These Terms to Your New Programs
- X
- X If you develop a new program, and you want it to be of the greatest
- Xpossible use to humanity, the best way to achieve this is to make it
- Xfree software which everyone can redistribute and change under these
- Xterms.
- X
- X To do so, attach the following notices to the program. It is safest to
- Xattach them to the start of each source file to most effectively convey
- Xthe exclusion of warranty; and each file should have at least the
- X"copyright" line and a pointer to where the full notice is found.
- X
- X <one line to give the program's name and a brief idea of what it does.>
- X Copyright (C) 19yy <name of author>
- X
- X This program is free software; you can redistribute it and/or modify
- X it under the terms of the GNU General Public License as published by
- X the Free Software Foundation; either version 1, or (at your option)
- X any later version.
- X
- X
- XAlso add information on how to contact you by electronic and paper mail.
- X
- XIf the program is interactive, make it output a short notice like this
- Xwhen it starts in an interactive mode:
- X
- X Gnomovision version 69, Copyright (C) 19xx name of author
- X Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- X This is free software, and you are welcome to redistribute it
- X under certain conditions; type `show c' for details.
- X
- XThe hypothetical commands `show w' and `show c' should show the
- Xappropriate parts of the General Public License. Of course, the
- Xcommands you use may be called something other than `show w' and `show
- Xc'; they could even be mouse-clicks or menu items--whatever suits your
- Xprogram.
- X
- XYou should also get your employer (if you work as a programmer) or your
- Xschool, if any, to sign a "copyright disclaimer" for the program, if
- Xnecessary. Here a sample; alter the names:
- X
- X Yoyodyne, Inc., hereby disclaims all copyright interest in the
- X program `Gnomovision' (a program to direct compilers to make passes
- X at assemblers) written by James Hacker.
- X
- X <signature of Ty Coon>, 1 April 1989
- X Ty Coon, President of Vice
- X
- XThat's all there is to it!
- X
- X
- END_OF_COPYING
- if test 12042 -ne `wc -c <COPYING`; then
- echo shar: \"COPYING\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f finger.c -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"finger.c\"
- else
- echo shar: Extracting \"finger.c\" \(13818 characters\)
- sed "s/^X//" >finger.c <<'END_OF_finger.c'
- X/*
- X * finger.c -- output formatting for finger (main is in args.c)
- X *
- X * Copyright (C) 1986, 1990 Philip L. Budne
- X *
- X * This file is part of "Phil's Finger Program".
- X *
- X * This program is free software; you can redistribute it and/or modify
- X * it under the terms of the GNU General Public License as published by
- X * the Free Software Foundation; either version 1, or (at your option)
- X * any later version.
- X *
- X */
- X
- X# ifndef lint
- Xstatic char *rcsid = "$Id: finger.c,v 3.0 90/07/06 13:10:35 budd Rel $";
- X# endif /* lint not defined */
- X
- X# include <sys/types.h>
- X# include <stdio.h>
- X# include "person.h"
- X# include "output.h"
- X# include "args.h" /* before luser.h */
- X# include "luser.h"
- X# include "finger.h"
- X# include "pr.h"
- X# include "inquire.h" /* for INQUIRE */
- X# include "ttylocfile.h"
- X
- X# define PID_COL /* display /pid in seperate column */
- X
- X/*# define RELATION /* display REL if this is defined */
- X/*# define REL_SUP "" /* (define as quoted string of relations */
- X /* to supress display of) */
- X
- XFORWARD LOCAL void
- X# ifdef RELATION
- X prelation(),
- X# endif /* RELATION defined */
- X pusername(), pgroup(), pspace(), ppname(),
- X pcmd(), pidle(), pbiff(), ptty(), pmesg(), plocation(), ppid(),
- X pstr(), pchar(), togoal();
- X
- XLOCAL int outcol, goalcol;
- X
- X# define USER_WID 8
- X# define PROG_WID 7 /* 6 prog + 1 flag */
- X
- X# ifndef TTY_WID
- X# ifdef AIX3
- X# define TTY_WID 6
- X# else /* AIX3 not defined */
- X# if defined(UmaxV) || defined(PTS_PTY_NAMES)
- X# define TTY_WID 5 /* rtAAPPS or ptsNN */
- X# else /* not defined(UmaxV) || defined(PTS_PTY_NAMES) */
- X# define TTY_WID 3
- X# endif /* not defined(UmaxV) || defined(PTS_PTY_NAMES) */
- X# endif /* AIX3 not defined */
- X# endif /* TTY_WID not defined */
- X
- X# define BASE_PER_WID (22+3+3) /* base person width */
- X
- Xtypedef void (*FPTR)();
- X
- XFPTR fields[] = {
- X pusername,
- X pspace,
- X pgroup,
- X# ifdef RELATION
- X# define GRPREL_WID 3 /* 2 + space */
- X prelation,
- X# else /* RELATION not defined */
- X# define GRPREL_WID 2 /* 1 + space */
- X# endif /* RELATION not defined */
- X pspace,
- X ppname,
- X NULL
- X}; /* fields */
- X
- X# define PER_WID (BASE_PER_WID-TTY_WID-GRPREL_WID)
- X
- X
- XFPTR fields2[] = {
- X# ifdef PID_COL
- X ppid,
- X# endif /* PID_COL defined */
- X# ifndef SUPPRESS_WHAT
- X pcmd,
- X# endif /* SUPPRESS_WHAT not defined */
- X pidle,
- X pbiff,
- X ptty,
- X pmesg,
- X plocation,
- X NULL
- X}; /* fields2 */
- X
- X/* display when program running from another uid */
- X# ifndef SUID_ROOT
- X# define SUID_ROOT '+'
- X# endif /* SUID_ROOT not defined */
- X
- X# ifndef SUID_OTHER
- X# define SUID_OTHER '!'
- X# endif /* SUID_OTHER not defined */
- X
- X/* when no command found */
- X# ifndef EMPTY_CMD
- X# define EMPTY_CMD "??"
- X# endif /* EMPTY_CMD not defined */
- X
- X# define NO_GROUP ' '
- X
- X# ifdef RELATION
- X# define REL_HEADER 'R'
- X# define GRP_HEADER 'G'
- X# else /* RELATION not defined */
- X# define GRP_HEADER ' ' /* or 'G' */
- X# endif /* RELATION not defined */
- X
- X/****** what to show when there is no person structure ******/
- X# define NO_RELATION ' '
- X
- X# ifdef INQUIRE
- X# define NO_NAME "--No inquire entry--"
- X# else /* INQUIRE not defined */
- X# define NO_NAME "--No password entry--" /* acucntrl locks?!*/
- X# endif /* INQUIRE not defined */
- X
- Xextern LTREE *maketree(); /* from getent.c */
- Xextern struct pr *getcommand(); /* from getcommand.c */
- Xextern char *getttyloc(); /* from gettyloc.c */
- Xextern int pwtree(); /* from getperson.c */
- Xextern whois(), plan(); /* from whois.c */
- Xextern char *gtname(), *intstr(); /* from output.c */
- X
- XLOCAL time_t now; /* current time */
- XLOCAL int personwidth; /* calculated at runtime! */
- X
- XLOCAL void /* forwards.. */
- X finguser(),
- X fingheader(),
- X dogecos();
- X
- XGLOBAL void dofinger( t )
- XLTREE *t;
- X{
- X int n;
- X
- X personwidth = PER_WID;
- X# ifdef PID_COL
- X# define PID_WID 6
- X if( sw_pid )
- X personwidth -= PID_WID/2;
- X# endif /* PID_COL defined */
- X
- X# ifdef LASTLOG
- X llopen(); /* open lastlog file */
- X# endif /* LASTLOG defined */
- X
- X time( &now ); /* get current time */
- X if( t == NULL ) /* nothing? */
- X pwtree( (t = maketree()) ); /* get tree of all logged in users */
- X
- X n = treesize( t ); /* count users */
- X if( n == 0 )
- X puts("No one logged in.");
- X else {
- X# ifndef ALWAYS_PRINT_HEADER
- X if( n > 1 ) /* be like oz finger */
- X# endif /* ALWAYS_PRINT_HEADER not defined */
- X fingheader(); /* print header */
- X
- X ptree( t, finguser ); /* print tree */
- X } /* n != 0 */
- X
- X# ifdef LASTLOG
- X llclose(); /* close lastlog file */
- X# endif /* LASTLOG defined */
- X} /* finger */
- X
- XLOCAL BOOL same;
- X
- XLOCAL void finguser(u)
- Xregister LUSER *u;
- X{
- X static PERSON *person;
- X static int incarnations;
- X register FPTR *fp;
- X
- X if( u->u_person != NULL ) {
- X if( (u->u_person->p_flags & P_RC) != 0 ) { /* pw_gecos == "RC" ?*/
- X dogecos( u );
- X return;
- X } /* RC hack */
- X } /* run command */
- X
- X if( u->u_flags & U_NLI ) { /* not logged in */
- X char location[ 50 ];
- X time_t ltime; /* last login time */
- X int host;
- X PERSON *p;
- X
- X p = u->u_person;
- X same = FALSE; /* crock, pass as arg? *TODO* */
- X for( fp = fields; *fp != NULL; fp++ )
- X (*fp)( FALSE, u, p );
- X goalcol++; /* space */
- X
- X /* get last login time from lastlog */
- X if( p == NULL || (p->p_flags & P_NOPWENT) )
- X pstr( "NO PASSWORD ENTRY (EXPIRED ACCOUNT?)" ); /* no pw ent? */
- X# ifdef LASTLOG
- X else if( !lltime( p->p_uid, location, <ime, &host ) || ltime == 0 )
- X pstr( "Login Unknown" ); /* no login time */
- X else { /* have login time. format it */
- X int printed;
- X TTYLOC *tp;
- X
- X pstr( "Login " );
- X pstr( nicetime( ltime ) );
- X
- X /* TODO: if sw_its no "from...." */
- X pstr( " from " );
- X printed = FALSE;
- X inittylocs();
- X if( !host && (tp = findttyloc( location )) != NULL ) {
- X char *s;
- X if( tp->t_short != NULL )
- X s = tp->t_short;
- X else if( tp->t_locn != NULL )
- X s = tp->t_locn;
- X else
- X s = NULL;
- X if( s != NULL ) {
- X printed = TRUE;
- X pstr( s );
- X pchar('{');
- X pstr( location );
- X pchar('}');
- X }
- X } /* foundttyloc */
- X if( !printed )
- X pstr( location );
- X } /* have login time */
- X# endif /* LASTLOG defined */
- X /* if sw_its check plan */
- X pchar('\n');
- X incarnations = 1;
- X } /* not logged in */
- X else { /* is logged in */
- X termstat( u ); /* get tty status (before getcommand) */
- X# ifndef SUPPRESS_WHAT
- X getcommand( u ); /* get command/daemon procs */
- X# endif /* SUPPRESS_WHAT not defined */
- X
- X# ifndef NEVER_SAME
- X if( u->u_person != NULL && u->u_person == person ) /* same person */
- X same = TRUE; /* as before? */
- X else
- X# endif /* NEVER_SAME not defined */
- X same = FALSE;
- X
- X person = u->u_person;
- X if( !same )
- X if( person != NULL )
- X incarnations = person->p_count;
- X else
- X incarnations = 1;
- X
- X for( fp = fields; *fp != NULL; fp++ )
- X (*fp)( FALSE, u, person );
- X goalcol++; /* blank space */
- X for( fp = fields2; *fp != NULL; fp++ )
- X (*fp)( FALSE, u, person );
- X pchar( '\n' );
- X } /* logged in */
- X
- X if( incarnations-- == 1 ) { /* final incarnation? */
- X if( sw_whois ) { /* do whois stuff */
- X whois( u );
- X blankline();
- X }
- X
- X if( u->u_sw.sw_mail || sw_whois || (u->u_flags & U_NLI) ) {
- X mcheck( u );
- X blankline();
- X }
- X
- X if( sw_whois ) {
- X remarks( u );
- X blankline();
- X }
- X
- X /*
- X * show plan if asked for. if user not logged in
- X * show unless prohibited.
- X */
- X if( u->u_sw.sw_plan || (u->u_flags & U_NLI) && !u->u_sw.sw_noplan ) {
- X plan( u );
- X blankline();
- X }
- X } /* last incarnation */
- X} /* finguser */
- X
- XLOCAL void fingheader() {
- X FPTR *fp;
- X
- X for( fp = fields; *fp != NULL; fp++ )
- X (*fp)( TRUE, NULL, NULL );
- X goalcol++; /* blank space */
- X for( fp = fields2; *fp != NULL; fp++ )
- X (*fp)( TRUE, NULL, NULL );
- X pchar( '\n' );
- X fflush(OUTPUT);
- X} /* fingheader */
- X
- XLOCAL void dogecos( u ) /* here if PNAME == "RC" */
- XLUSER *u;
- X{
- X int pid, wpid;
- X
- X pid = fork(); /* no vfork uses stdio */
- X if( pid == 0 ) { /* be childish */
- X PERSON *p;
- X p = u->u_person;
- X
- X chdir(p->p_home);
- X setuid(p->p_uid);
- X setgid(p->p_gid);
- X printf("%s/%s:\n", p->p_home, u->u_user);
- X fflush( stdout );
- X execl(u->u_user, u->u_user, 0);
- X perror("Sorry");
- X exit(1);
- X }
- X else if( pid < 0 )
- X perror("fork");
- X
- X while( (wpid = wait(0)) > 0 && wpid != pid ) /* lassie come home!! */
- X ;
- X} /* dogecos */
- X
- XLOCAL void
- X_pchar( c )
- X char c;
- X{
- X static char linebuf[ 512 ], *lp = linebuf;
- X if( c == '\n' ) {
- X *lp = EOS;
- X outline( linebuf );
- X outcol = goalcol = 0;
- X lp = linebuf;
- X } /* newline */
- X else { /* not newline */
- X if( c == '\t' )
- X outcol = (outcol + 8) & ~7;
- X else
- X outcol++;
- X *lp++ = c;
- X } /* not newline */
- X} /* _pchar */
- X
- XLOCAL void
- Xtogoal() {
- X while( outcol < goalcol ) {
- X int temp;
- X temp = (outcol + 8) & ~7;
- X if( temp <= goalcol )
- X _pchar( '\t' );
- X else
- X _pchar( ' ' );
- X }
- X goalcol = outcol;
- X} /* togoal */
- X
- XLOCAL void
- Xpchar( c )
- X char c;
- X{
- X if( outcol < goalcol ) /* save extra calls */
- X togoal();
- X _pchar( c );
- X} /* pchar */
- X
- XLOCAL void
- Xpstr( s )
- X register char *s;
- X{
- X if( s == NULL )
- X return;
- X togoal();
- X while( *s )
- X _pchar( *s++ );
- X} /* pstr */
- X
- XLOCAL void
- Xpcount( c, s )
- X register c;
- X register char *s;
- X{
- X if( s == NULL )
- X return;
- X togoal();
- X while( c-- && *s )
- X _pchar( *s++ );
- X} /* pcount */
- X
- XLOCAL void
- Xpusername( title, u, p )
- X BOOL title;
- X LUSER *u;
- X PERSON *p;
- X{
- X if( title )
- X pstr( "-User-" );
- X else if( !same )
- X pcount( USER_WID, u->u_user );
- X goalcol += USER_WID;
- X} /* pusername */
- X
- X# ifdef INQUIRE
- X# ifdef RELATION
- XLOCAL void
- Xprelation( title, u, p )
- X BOOL title;
- X LUSER *u;
- X PERSON *p;
- X{
- X char rel;
- X if( title )
- X pchar( REL_HEADER ); /* title */
- X else if( !same ) /* not same as last */
- X if( p != NULL ) { /* have person info */
- X rel = p->p_relation;
- X# ifdef REL_SUP
- X if( sw_whois || index(REL_SUP, rel) == NULL ) /* whois or */
- X# endif /* REL_SUP defined */
- X pchar( rel ); /* not suppressed */
- X } /* have person */
- X else
- X pchar( NO_REL );
- X goalcol++;
- X} /* prelation */
- X# endif /* RELATION defined */
- X# endif /* INQUIRE defined */
- X
- XLOCAL void
- Xpgroup( title, u, p )
- X BOOL title;
- X LUSER *u;
- X PERSON *p;
- X{
- X
- X if( title )
- X pchar( GRP_HEADER ); /* title */
- X else if( !same && p != NULL ) /* not same and have person */
- X pchar( p->p_group );
- X
- X goalcol++;
- X} /* pgroup */
- X
- XLOCAL void
- Xpspace( title, u, p )
- X BOOL title;
- X LUSER *u;
- X PERSON *p;
- X{
- X goalcol++;
- X} /* pspace */
- X
- XLOCAL void
- Xppname( title, u, p )
- X BOOL title;
- X LUSER *u;
- X PERSON *p;
- X{
- X if( title )
- X pstr( "--Full name--" );
- X else if( !same )
- X if( p != NULL )
- X pcount( personwidth, p->p_personal );
- X else
- X pstr( NO_NAME );
- X goalcol += personwidth;
- X} /* ppname */
- X
- XLOCAL void
- Xpcmd( title, u, p )
- X BOOL title;
- X LUSER *u;
- X PERSON *p;
- X{
- X struct pr *pr;
- X
- X if( title ) {
- X pstr( (sw_its ? "Jobnam" : "-What-") );
- X goalcol += PROG_WID;
- X return;
- X }
- X
- X pr = u->u_command;
- X if( pr != NULL ) {
- X char suid;
- X
- X if( p == NULL || pr->pr_uid == p->p_uid ) /* same uid? */
- X suid = ' '; /* no flag */
- X else if( pr->pr_uid == 0 ) /* super user? */
- X suid = SUID_ROOT; /* flag it */
- X else /* someone else */
- X suid = SUID_OTHER;
- X
- X pcount( PROG_WID-1, pr->pr_cmd ); /* leave one for suid */
- X pchar( suid );
- X } /* pr not null */
- X else
- X pstr( EMPTY_CMD );
- X
- X goalcol += PROG_WID;
- X} /* pcmd */
- X
- X# ifdef PID_COL
- XLOCAL void
- Xppid( title, u, p )
- X BOOL title;
- X LUSER *u;
- X PERSON *p;
- X{
- X if( !sw_pid )
- X return; /* takes no space!! */
- X
- X if( title )
- X pstr(" Pid"); /* two leading spaces */
- X else if( u->u_command != NULL ) {
- X char tbuf[10];
- X sprintf(tbuf, "%5d", u->u_command->pr_pid );
- X pstr( tbuf );
- X }
- X goalcol += PID_WID; /* leave space after */
- X} /* ppid */
- X# endif /* PID_COL defined */
- X
- XLOCAL void
- Xpidle( title, u, p )
- X BOOL title;
- X LUSER *u;
- X PERSON *p;
- X{
- X if( title ) {
- X if( sw_age )
- X pstr( "-On-" );
- X else if( sw_state )
- X pstr( "Stat" );
- X# ifndef PID_COL
- X else if( sw_pid )
- X pstr( " Pid" ); /* two spaces!! */
- X# endif /* PID_COL not defined */
- X else
- X pstr( "Idle" );
- X } /* title */
- X else { /* real thing */
- X char idbuf[ 100 ];
- X strcpy( idbuf, "??" );
- X
- X if( sw_age )
- X intstr(idbuf, now - u->u_time ); /* get time on */
- X else if( sw_state ) {
- X if( u->u_command != NULL )
- X getstate( idbuf, u->u_command ); /* get state */
- X }
- X# ifndef PID_COL
- X else if( sw_pid ) {
- X if( u->u_command != NULL )
- X sprintf(idbuf, "%5d", u->u_command->pr_pid );
- X }
- X# endif /* PID_COL not defined */
- X else if( u->u_flags & U_BADTTY )
- X strcpy( idbuf, "*:**" );
- X else
- X intstr(idbuf, u->u_idle ); /* get idle time */
- X pstr( idbuf );
- X }
- X
- X# ifndef PID_COL
- X if( sw_pid ) /* variable width!! */
- X goalcol += 5;
- X else
- X# endif /* PID_COL not defined */
- X goalcol += 4;
- X} /* pidle */
- X
- XLOCAL void
- Xpbiff( title, u, p )
- X BOOL title;
- X LUSER *u;
- X PERSON *p;
- X{
- X /* alright, I lost control. C at its ugliest
- X * nothing - space
- X * biff - dot
- X * hungry - comma
- X * both - semi
- X */
- X if( !title )
- X pchar( " .,;"[ ((u->u_flags & U_BIFF) ? 01 : 0) |
- X ((u->u_flags & U_HUNGRY) ? 02 : 0) ] );
- X goalcol++;
- X} /* pbiff */
- X
- XLOCAL void
- Xptty( title, u, p )
- X BOOL title;
- X LUSER *u;
- X PERSON *p;
- X{
- X if( title )
- X pstr("TTY");
- X else
- X pcount( TTY_WID, gtname( u->u_line ) ); /* get trimmed tty name */
- X goalcol += TTY_WID;
- X} /* ptty */
- X
- XLOCAL void
- Xpmesg( title, u, p )
- X BOOL title;
- X LUSER *u;
- X PERSON *p;
- X{
- X if( !title && (u->u_flags & U_NOWRITE) )
- X pchar( '*' );
- X goalcol++;
- X} /* pmesg */
- X
- XLOCAL void
- Xplocation( title, u, p )
- X BOOL title;
- X LUSER *u;
- X PERSON *p;
- X{
- X if( title )
- X pstr( "-Console Location-" );
- X else
- X pstr( getttyloc( u ) ); /* tty location */
- X /* no new goal!! */
- X} /* plocation */
- X
- X/*
- X * Local variables:
- X * comment-column: 40
- X * End:
- X */
- END_OF_finger.c
- if test 13818 -ne `wc -c <finger.c`; then
- echo shar: \"finger.c\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f fingerd.c -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"fingerd.c\"
- else
- echo shar: Extracting \"fingerd.c\" \(13848 characters\)
- sed "s/^X//" >fingerd.c <<'END_OF_fingerd.c'
- X/*
- X * fingerd.c - finger server
- X * Barry Shein/Phil Budne, Boston University
- X *
- X * Should conform to RFC742 (which is a pretty vague thing)
- X *
- X * Copyright (c) 1986, 1990 Barry Z. Shein & Philip L. Budne
- X */
- X
- X# ifndef lint
- Xstatic char *rcsid = "$Id: fingerd.c,v 3.0 90/07/06 13:10:44 budd Rel $";
- X# endif /* lint not defined */
- X
- X# include "finger.h"
- X
- X# include <stdio.h>
- X# include <sys/types.h>
- X# include <netinet/in.h> /* sockaddr_in, IPPORT_FINGER */
- X# include <sys/socket.h> /* AF_... */
- X# include <strings.h> /* index */
- X# include <errno.h> /* EINTR */
- X# include <pwd.h> /* lookup nobody */
- X
- X# ifndef INETD
- X# include <sys/ioctl.h> /* TIOCNOTTY */
- X# include <signal.h> /* SIGCHLD */
- X# ifndef NO_WAIT_H
- X# include <sys/wait.h> /* WNOHANG... */
- X# endif /* NO_WAIT_H not defined */
- X
- XFORWARD LOCAL void fireman();
- X# endif /* INETD not defined */
- X
- X/*
- X * BZS - optional SYSLOG'ing of connections
- X */
- X# ifdef SYSLOG
- X# include <syslog.h> /* LOG_... */
- X# include <netdb.h> /* gethostbyaddr */
- X
- XFORWARD LOCAL void logit();
- X# endif /* SYSLOG defined */
- X
- X# ifdef USG
- X# define vfork fork
- X# endif /* USG defined */
- X
- X# ifndef MONNAME /* ie SYSTEM:MONNAM.TXT */
- X# define MONNAME "/etc/monnam" /* System name */
- X# endif /* MONNAME not defined */
- X
- X# ifndef NOLOGIN
- X# define NOLOGIN "/etc/nologin"
- X# endif /* NOLOGIN not defined */
- X
- X# define SERVICE "finger" /* for getservent */
- X# define PROTOCOL "tcp"
- X
- X# ifndef IPPORT_FINGER /* if services deficient */
- X# define IPPORT_FINGER 79 /* usually in netinet/in.h */
- X# endif /* IPPORT_FINGER not defined */
- X
- X# ifndef UID_NOBODY
- X# define UID_NOBODY -2
- X# endif /* UID_NOBODY not defined */
- X
- X# ifndef USER_NOBODY
- X# define USER_NOBODY "nobody"
- X# endif /* USER_NOBODY not defined */
- X
- X
- X# define BACKLOG 5 /* max under 4.2 */
- X
- X/*
- X * Arbitrary...
- X */
- X# define MAXNAMES 100
- X# define MAXHERALD 100
- X
- X/****************************************************************/
- X
- X# ifdef UTSNAME
- X# include <sys/utsname.h>
- X# else /* UTSNAME not defined */
- X
- X/* perhaps ARCHITECTURE should be split into MFGR and MACHINE? */
- X
- X# ifdef sun
- X# ifdef mc68010
- X# define ARCHITECTURE "Sun-2"
- X# endif /* mc68010 defined */
- X# ifdef mc68020
- X# define ARCHITECTURE "Sun-3"
- X# endif /* mc68020 defined */
- X# ifdef sparc
- X# define ARCHITECTURE "Sun-4"
- X# endif /* sparc defined */
- X# ifdef i386
- X# define ARCHITECTURE "Sun 386i" /* "Road Runner"? */
- X# endif /* i386 defined */
- X# ifndef ARCHITECTURE
- X# define ARCHITECTURE "Sun"
- X# endif /* ARCHITECTURE not defined */
- X# endif /* sun defined */
- X
- X# ifdef ibm032
- X# define ARCHITECTURE "IBM ROMP"
- X# endif /* ibm032 defined */
- X
- X# ifdef u3b
- X# define ARCHITECTURE "AT&T 3B"
- X# endif /* u3b defined */
- X
- X# ifdef u370
- X# define ARCHITECTURE "IBM S/370"
- X# endif /* u370 defined */
- X
- X# ifdef pdp11
- X# define ARCHITECTURE "PDP-11"
- X# endif /* pdp11 defined */
- X
- X# ifdef accel
- X# define ARCHITECTURE "Celerity Accel"
- X# endif /* accel defined */
- X
- X# ifndef ARCHITECTURE
- X
- X# ifdef vax
- X# define ARCHITECTURE "VAX"
- X# endif /* vax defined */
- X
- X# if defined(n16) || defined(ns32000) || defined(ns32032) || defined(ns32332)
- X# define ARCHITECTURE "NS32k"
- X# endif /* defined(n16) || defined(ns32000) || defined(ns32032) || defined(ns32332) */
- X
- X# ifdef mips
- X# define ARCHITECTURE "MIPS"
- X# endif /* mips defined */
- X
- X# ifdef sparc
- X# define ARCHITECTURE "SPARC"
- X# endif /* sparc defined */
- X
- X# if defined(mc68000) || defined(mc68020)
- X# define ARCHITECTURE "MC68k"
- X# endif /* defined(mc68000) || defined(mc68020) */
- X
- X# ifdef i386
- X# define ARCHITECTURE "i386"
- X# endif /* i386 defined */
- X
- X# endif /* ARCHITECTURE not defined */
- X
- X/****************************************************************/
- X
- X# ifdef bsd4_3
- X# define DEFHERALD "4.3 BSD"
- X# endif /* bsd4_3 defined */
- X
- X# if SunOS >= 400
- X# define DEFHERALD "SunOS 4.0" /* 4.1 has uname(2) */
- X# endif /* SunOS >= 400 */
- X
- X# ifdef USG
- X# define DEFHERALD "USG"
- X# endif /* USG defined */
- X
- X# ifdef sequent
- X# define DEFHERALD "Sequent Dynix"
- X# endif /* sequent defined */
- X
- X# if Umax == 42
- X# define DEFHERALD "Encore Umax 4.2"
- X# endif /* Umax == 42 */
- X
- X# if Umax == 43
- X# define DEFHERALD "Encore Umax 4.3"
- X# endif /* Umax == 43 */
- X
- X# ifdef ultrix /* Digital's big ideas */
- X
- X# define DEFHERALD "Ultrix" /* Ultrix has uname(2) */
- X# endif /* ultrix defined */
- X
- X# ifdef sony_news
- X# define DEFHERALD "Sony NewsOS"
- X# endif /* sony_news defined */
- X
- X# ifndef DEFHERALD /* the default default herald!! */
- X# define DEFHERALD "4.2 BSD"
- X# endif /* DEFHERALD not defined */
- X
- X# endif /* UTSNAME not defined */
- X
- Xchar herald[MAXHERALD];
- Xextern int errno, sys_nerr;
- Xchar *sys_errlist[];
- X
- X/*
- X * Program we will fork to actually do the lookups
- X */
- Xchar *fingerpaths[] = {
- X# ifdef FINGERPATHS
- X FINGERPATHS , /* alternate finger paths */
- X# endif /* FINGERPATHS defined */
- X "/usr/local/bin/finger",
- X "/usr/local/finger",
- X "/usr/bin/finger",
- X "/usr/ucb/finger",
- X
- X "/usr/local/bin/xf",
- X "/usr/local/xf",
- X "/usr/bin/xf",
- X "/usr/ucb/xf",
- X
- X "/usr/ucb/w",
- X "/bin/who",
- X NULL
- X};
- X
- X/* argv[0] for above
- X# ifndef FINGER0
- X# define FINGER0 "finger"
- X# endif /* FINGER0 not defined */
- X
- X/*
- X * Program to print pretty hello message
- X */
- X
- X# ifndef UPTIME
- X# define UPTIME "/usr/ucb/uptime" /* define this to print ldav, uptime */
- X# endif /* UPTIME not defined */
- X
- X# ifndef UPTIME0
- X# define UPTIME0 "uptime"
- X# endif /* UPTIME0 not defined */
- X
- Xint debug;
- X
- XFORWARD LOCAL void Perror(), fperror(), iniherald(), doit(), pherald();
- X
- Xint main( argc, argv )
- X int argc;
- X char *argv[];
- X{
- X# ifdef INETD
- X iniherald();
- X doit( 0 );
- X exit( 0 );
- X# else /* INETD not defined */
- X int i, f;
- X
- X iniherald();
- X /*
- X * skip detaching the tty if first arg '-d'
- X */
- X if( (argc > 1) && (argv[1][0] == '-') && (argv[1][1] == 'd'))
- X debug = 1;
- X else
- X debug = 0;
- X
- X /*
- X * After forking, child detaches controlling
- X * terminal, parent exits, we are free
- X */
- X if( !debug ) {
- X switch( fork() ) {
- X case 0: /* parent */
- X exit( 0 );
- X
- X case -1:
- X Perror( "fork1" );
- X } /* switch */
- X
- X# ifdef USG
- X f = 32; /* FIXME! */
- X# else /* USG not defined */
- X f = getdtablesize();
- X# endif /* USG not defined */
- X for( i = 0; i < f; i++ )
- X (void) close( i );
- X
- X /*
- X * No one can hear you scream in space....
- X */
- X (void) open("/", 1);
- X# ifdef USG /* FIXME! */
- X (void) dup( 0 );
- X (void) dup( 0 );
- X# else /* USG not defined */
- X (void) dup2(0, 1);
- X (void) dup2(0, 2);
- X# endif /* USG not defined */
- X
- X# ifdef TIOCNOTTY
- X if( (i = open("/dev/tty",2)) >= 0 ) {
- X (void) ioctl(i,TIOCNOTTY,0);
- X (void) close(i);
- X } /* tty open */
- X# endif /* TIOCNOTTY defined */
- X# ifdef USG
- X setpgrp();
- X# endif /* USG defined */
- X } /* not debug */
- X
- X signal(SIGCHLD, fireman);
- X f = getsocket();
- X listen(f,BACKLOG);
- X for( ; ; ) {
- X int g, szfrom;
- X struct sockaddr_in from;
- X
- X szfrom = sizeof( from );
- X if( (g = accept(f, &from, &szfrom)) < 0 ) {
- X if(errno != EINTR)
- X Perror("accept");
- X continue;
- X } /* accept */
- X switch( fork() ) {
- X case 0:
- X (void) close( f );
- X doit( g );
- X exit( 1 ); /* SHOULDNT HAPPEN */
- X
- X case -1:
- X Perror( "fork2" );
- X break;
- X } /* fork switch */
- X (void) close(g);
- X } /* for ever */
- X /*NOTREACHED*/
- X# endif /* INETD not defined */
- X return( 0 ); /* be ANSI, keep gcc quiet! */
- X} /* main */
- X
- X/*
- X * doit -- forked to actually satisfy request
- X */
- XLOCAL void doit( s )
- X int s;
- X{
- X char buf[BUFSIZ+1];
- X char *av[MAXNAMES+2], *ep[1];
- X register int i;
- X register char *bp, **pp;
- X int uid = UID_NOBODY;
- X# ifdef USER_NOBODY
- X struct passwd *pw;
- X# endif /* USER_NOBODY defined */
- X
- X (void) dup2( s, 1 ); /* dup socket onto stdout */
- X (void) dup2( s, 2 ); /* and stderr */
- X pherald();
- X
- X /*
- X * Note: this assumes request is sent in one shot
- X * which is consistent with RFC742.
- X *
- X * Never used gets() so never had worm hole!!
- X */
- X if( (i = read( s, buf, BUFSIZ)) < 0 )
- X fperror("could not read request");
- X buf[i] = EOS; /* tie off buf */
- X
- X /*
- X * Make an argv list breaking at any space or ctrl chars
- X * This is slightly more liberal than RFC742:
- X * name,name,name is ok (RFC742)
- X * so is
- X * name name name
- X * and by default things like:
- X * name\nname\n
- X * name\r\nname\r\n
- X */
- X i = 1;
- X bp = buf;
- X while( *bp != EOS ) {
- X while( (*bp <= ' ') || (*bp == ',') ) {
- X if(*bp == EOS)
- X break;
- X else
- X *bp = EOS;
- X bp++;
- X } /* while non print or comma */
- X if(*bp == EOS)
- X break;
- X av[i++] = bp;
- X if(i == MAXNAMES)
- X break;
- X while((*bp > ' ') && (*bp != ','))
- X bp++;
- X } /* while bp */
- X av[i] = NULL; /* tie off argv */
- X ep[0] = NULL; /* null environment */
- X
- X# ifdef SYSLOG
- X logit( s, av);
- X# endif /* SYSLOG defined */
- X
- X# ifdef USER_NOBODY
- X if( (pw = getpwnam( USER_NOBODY )) != NULL )
- X uid = pw->pw_uid;
- X# endif /* USER_NOBODY defined */
- X setuid( uid ); /* become noone -- so we are under */
- X /* control of maxuprc */
- X
- X for( pp = fingerpaths; *pp != NULL; pp++ ) {
- X av[0] = *pp;
- X execv(*pp, av);
- X } /* for fingerpaths */
- X /*
- X * ERROR
- X */
- X puts("Could not find local finger program.");
- X fflush( stdout );
- X# ifdef SYSLOG
- X syslog( LOG_ERR, "Could not find local finger program" );
- X# endif /* SYSLOG defined */
- X _exit( 1 );
- X} /* doit */
- X
- XLOCAL void pherald() { /* print herald */
- X int fk;
- X FILE *fd;
- X char *ep[1];
- X
- X ep[0] = NULL;
- X printf( "%s\r\n", herald );
- X fflush( stdout );
- X
- X# ifdef UPTIME
- X if( (fk = vfork()) == 0 ) {
- X execl(UPTIME, UPTIME0, 0 );
- X fperror(UPTIME);
- X }
- X else if( fk != -1 ) {
- X int wf;
- X while( (wf = wait(0)) != -1 && (wf != fk) )
- X ;
- X putchar( '\r' ); /* assume last char was \n */
- X }
- X else
- X Perror("fork3");
- X# endif /* UPTIME defined */
- X
- X# ifdef NOLOGIN
- X if( (fd = fopen(NOLOGIN, "r")) != NULL ) {
- X register c, lc;
- X
- X fputs( "\r\nNo Logins:\r\n", stdout );
- X
- X lc = -1; /* zap last char */
- X while( (c = getc( fd )) != EOF ) {
- X if( c == '\n' )
- X putchar( '\r' );
- X putchar( c ); /* output char */
- X lc = c; /* save it */
- X } /* while */
- X fclose( fd ); /* close file */
- X
- X if( lc != '\n' ) { /* was last a newline? */
- X putchar( '\r' );
- X putchar( '\n' ); /* no, output one now */
- X }
- X
- X /* WISH: perhaps print /etc/motd here too? */
- X } /* opened NOLOGIN */
- X# endif /* NOLOGIN defined */
- X
- X putchar( '\r' );
- X putchar( '\n' ); /* blank line */
- X fflush( stdout );
- X} /* pherald */
- X
- XLOCAL void iniherald() { /* create herald string once */
- X int f;
- X char namebuf[200];
- X# ifdef UTSNAME
- X struct utsname uts;
- X
- X uname( &uts );
- X strcpy( herald, uts.nodename );
- X# else /* UTSNAME not defined */
- X char myname[MAXHOSTLEN];
- X
- X gethostname(myname, sizeof( myname ) );
- X strcpy(herald, myname );
- X# endif /* UTSNAME not defined */
- X strcat(herald, " -- ");
- X
- X if( (f = open(MONNAME, 0)) >= 0 &&
- X read(f, namebuf, sizeof( namebuf) -1 ) > 0 ) {
- X char *cp;
- X
- X if( (cp = index(namebuf, '\n')) != NULL )
- X *cp = EOS;
- X
- X strcat(herald, namebuf);
- X close( f );
- X } /* got MONNAME */
- X else {
- X# ifdef UTSNAME
- X strcat(herald, uts.machine);
- X if( strcmp( uts.sysname, uts.nodename ) != 0 ) { /* SVR2?! */
- X strcat(herald, " " );
- X strcat(herald, uts.sysname );
- X }
- X strcat(herald, " release " );
- X strcat(herald, uts.release );
- X# ifdef UmaxV
- X if( strcmp( uts.release, uts.version ) != 0 )
- X# endif /* UmaxV defined */
- X strcat(herald, " version " ),
- X strcat(herald, uts.version );
- X# else /* UTSNAME not defined */
- X strcat(herald, DEFHERALD );
- X# ifdef ARCHITECTURE
- X strcat(herald, " " );
- X strcat(herald, ARCHITECTURE );
- X# endif /* ARCHITECTURE defined */
- X# endif /* UTSNAME not defined */
- X } /* no MONNAME */
- X} /* iniherald */
- X
- X# ifndef INETD
- Xgetsocket() {
- X int f;
- X struct servent *sp;
- X struct sockaddr_in sin;
- X
- X bzero(&sin,sizeof sin);
- X sin.sin_family = AF_INET;
- X
- X if( (sp = getservbyname( SERVICE, PROTOCOL )) == NULL)
- X sin.sin_port = sp->s_port;
- X else
- X sin.sin_port = htons( IPPORT_FINGER );
- X
- X if( (f = socket(AF_INET,SOCK_STREAM,0)) < 0)
- X fperror("socket");
- X
- X if(bind(f,(caddr_t)&sin,sizeof sin,0) < 0)
- X fperror("bind");
- X
- X return( f );
- X} /* getsocket */
- X
- XLOCAL void fireman() { /* catch falling babies */
- X# ifdef NO_WAIT_H
- X int w;
- X
- X while( wait(&w) > 0 )
- X ;
- X# else /* NO_WAIT_H not defined */
- X union wait status;
- X
- X while( wait3( &status, WNOHANG|WUNTRACED, 0) > 0 )
- X ;
- X# endif /* NO_WAIT_H not defined */
- X} /* catchchild */
- X# endif /* INETD not defined */
- X
- X# ifdef SYSLOG
- XLOCAL void logit(s, av)
- X int s;
- X register char **av;
- X{
- X int i;
- X struct hostent *hp;
- X char buffer[ 1024 ];
- X struct sockaddr_in peer;
- X char *name, *inet_ntoa();
- X
- X i = sizeof( peer );
- X if( getpeername( s, &peer, &i) != 0 )
- X return;
- X
- X# ifdef LOG_DAEMON
- X if( openlog( "fingerd", 0, LOG_DAEMON ) != 0 )
- X return;
- X# else /* LOG_DAEMON not defined */
- X if( openlog( "fingerd", 0) != 0 )
- X return;
- X# endif /* LOG_DAEMON not defined */
- X
- X hp = gethostbyaddr( (char *)&peer.sin_addr, sizeof(peer.sin_addr), AF_INET);
- X if( hp == NULL)
- X name = inet_ntoa( peer.sin_addr );
- X else
- X name = hp->h_name;
- X
- X buffer[0] = EOS;
- X av++; /* skip argv[0] */
- X while( *av != NULL ) {
- X if( buffer[0] != EOS )
- X strcat( buffer, " " );
- X strcat( buffer, *av++ );
- X } /* while av */
- X
- X syslog( LOG_INFO, "%s: '%s'", name, buffer );
- X} /* logit */
- X# endif /* SYSLOG defined */
- X
- XLOCAL void Perror( s ) /* print error */
- X char *s;
- X{
- X# ifdef SYSLOG
- X syslog( LOG_ERR, "%s: %m", s );
- X# endif /* SYSLOG defined */
- X
- X if( errno < 1 || errno > sys_nerr )
- X fprintf( stderr, "fingerd: %s -- error %d\n", s, errno );
- X else
- X fprintf( stderr, "fingerd: %s -- %s\n", s, sys_errlist[ errno ] );
- X} /* Perror */
- X
- XLOCAL void fperror( s ) /* fatal Perror */
- X char *s;
- X{
- X Perror( s );
- X exit( 1 );
- X}/* fperror */
- X
- X/*
- X * Local variables:
- X * comment-column: 40
- X * End:
- X */
- END_OF_fingerd.c
- if test 13848 -ne `wc -c <fingerd.c`; then
- echo shar: \"fingerd.c\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- if test -f getcommand.c -a "${1}" != "-c" ; then
- echo shar: Will not over-write existing file \"getcommand.c\"
- else
- echo shar: Extracting \"getcommand.c\" \(14997 characters\)
- sed "s/^X//" >getcommand.c <<'END_OF_getcommand.c'
- X/*
- X * getcommand.c - return current command given a LUSER
- X *
- X * Copyright (C) 1986, 1990 Philip L. Budne
- X *
- X * This file is part of "Phil's Finger Program".
- X *
- X * This program is free software; you can redistribute it and/or modify
- X * it under the terms of the GNU General Public License as published by
- X * the Free Software Foundation; either version 1, or (at your option)
- X * any later version.
- X *
- X */
- X
- X# ifndef lint
- Xstatic char *rcsid = "$Id: getcommand.c,v 3.0 90/07/06 13:10:45 budd Rel $";
- X# endif /* lint not defined */
- X
- X# include "finger.h"
- X
- X# ifndef Umax
- X# include "ustruct.h"
- X# else /* Umax defined */
- X# if Umax == 42
- X# include <sys/signal.h> /* for SIGxxx */
- X# include <sys/pmdefs.h> /* for SSTOP, procstates */
- X# include <sys/time.h> /* for statistics */
- X# include <sys/types.h> /* for dev_t */
- X# include <sys/statistics.h> /* for inq_stats */
- X# include <sys/procstats.h> /* for inq_stats */
- X# endif /* Umax == 42 */
- X# if Umax == 43
- X# include <sys/signal.h> /* for SIGxxx */
- X# define KERNEL
- X# include <sys/types.h>
- X# undef KERNEL
- X# include <sys/time.h>
- X# include <sys/resource.h>
- X# include <sys/proc.h> /* Sxxx */
- X# include <inq_stats/statistics.h>
- X# include <inq_stats/procstats.h>
- X# ifndef SSLEEP
- X# define SSLEEP 1
- X# endif /* SSLEEP not defined */
- X# endif /* Umax == 43 */
- X# endif /* Umax defined */
- X
- X# include <stdio.h>
- X# include "args.h" /* before luser.h */
- X# include "luser.h"
- X# include "pr.h"
- X# include "daemon.h"
- X# define WAITSTATENAME waitstatename /* for waitstate.h */
- X# include "waitstate.h"
- X
- X# ifdef Umax
- X# include <sys/ioctl.h> /* to get pgrp!!! */
- X# define MAXP 100
- XLOCAL struct pr prvec[ MAXP ]; /* per terminal process table */
- X# else /* Umax not defined */
- X# include "kmem.h"
- Xextern FTYPE kmem; /* from kmem.c */
- Xextern struct pr *readpr(); /* from readpr.c */
- Xextern waitstate_t waitstate(); /* from readpr.c */
- X
- XLOCAL struct pr *prvec; /* vector of processes */
- XLOCAL int initialized; /* true if have done readpr() */
- X# endif /* Umax not defined */
- X
- X# if Umax != 42
- XLOCAL char *procstates[] = {
- X "?0", "SL",
- X# ifdef SVR3_STATES
- X
- X "RU", "ZO", "ST", "ID", "ON", "SX",
- X# ifdef UmaxV
- X "BS",
- X# endif /* UmaxV defined */
- X
- X# else /* SVR3_STATES not defined */
- X
- X /* SVR2 and BSD */
- X "WA", "RU", "ID",
- X# if Umax == 43
- X "ST", "EX", "EV",
- X# else /* not Umax == 43 */
- X "ZO", "ST",
- X# ifdef AIX_RT
- X "?7", "?8", "?9", "SK",
- X# endif /* AIX_RT defined */
- X# endif /* not Umax == 43 */
- X
- X# endif /* SVR3_STATES not defined */
- X "**" };
- X# endif /* Umax != 42 */
- X
- X# ifdef sun
- Xextern dev_t consdev;
- Xextern dev_t rconsdev;
- Xextern dev_t dev_console;
- X# endif /* sun defined */
- X
- X# ifndef PID_T
- X# define PID_T short
- X# endif /* PID_T not defined */
- X
- X# ifndef PID_BITS
- X# define PID_BITS 15 /* most Unices only go up to 30000 */
- X# endif /* PID_BITS not defined */
- X
- XLOCAL char *hidden[] = {
- X# ifdef IN_DOT_SERVER
- X "in.comsat",
- X "in.syslog",
- X "in.talkd",
- X "in.rlogind",
- X "in.telnetd",
- X# else /* IN_DOT_SERVER not defined */
- X "comsat",
- X "syslogd",
- X "talkd",
- X "ntalkd", /* 4.3 */
- X "rlogind",
- X "telnetd",
- X# endif /* IN_DOT_SERVER not defined */
- X# ifdef sun
- X "selection_svc", /* SunView barfage */
- X# endif /* sun defined */
- X# ifdef HIDDEN_PROGRAMS
- X HIDDEN_PROGRAMS,
- X# endif /* HIDDEN_PROGRAMS defined */
- X NULL
- X};
- X
- XLOCAL struct pr *getcommand2();
- X
- X/*
- X * given a luser, return pr struct for executing command.
- X *
- X * getcommand is a jacket for getcommand2 which finds the
- X * process. we then trace back for process parent, and mark in
- X * luser struct for potential use in printing ttyloc.
- X */
- X
- XGLOBAL struct pr *getcommand( u )
- XLUSER *u;
- X{
- X struct pr *p2, *lastpr;
- X register struct pr *pr;
- X PID_T pp;
- X
- X u->u_command = u->u_daemonp = NULL;
- X u->u_daemon = NULL;
- X
- X if( (p2 = getcommand2( u )) == NULL )
- X return( NULL );
- X u->u_command = p2;
- X
- X /* only do this for lusers on ptys? *TODO* */
- X pp = p2->pr_ppid;
- X lastpr = NULL;
- X while( pp != INIT_PID && pp > 0 ) {
- X register struct daemon *dp;
- X
- X for( pr = prvec; pr->pr_stat != 0; pr++ ) /* search process table */
- X if( pr->pr_pid == pp ) /* for parent process pid */
- X break;
- X
- X if( pr->pr_pid != pp ) /* did not find parent? */
- X break; /* (parent did not have a tty..) */
- X
- X lastpr = pr; /* save most 'recent' ancestor */
- X /* here with parent, check for daemon-ness */
- X for( dp = daemons; dp->d_cmd != NULL; dp++ )
- X/* printf("%d %s %s\n", pp, pr->pr_cmd, dp->d_cmd );/**/
- X if( pr->pr_cmd[0] == dp->d_cmd[0] && /* quick test */
- X strcmp( pr->pr_cmd, dp->d_cmd ) == 0 ) {
- X u->u_daemon = dp; /* save daemon type */
- X u->u_daemonp = pr; /* save process for kicks */
- X return( p2 ); /* need goto to leave 2 loops */
- X } /* daemon match */
- X pp = pr->pr_ppid; /* keep moving up process tree */
- X } /* while dp */
- X
- X /* catch things not in daemons[] */
- X /* (*) perhaps flush INIT_PID test? */
- X if( lastpr != NULL &&
- X pp == INIT_PID ) /* child of init (*) */
- X u->u_daemonp = lastpr; /* save for possible display */
- X return( p2 );
- X} /* getcommand */
- X
- X/*
- X * locate "current" process on a tty.
- X * requires many silly heuristics.
- X */
- X
- XLOCAL struct pr *getcommand2( u )
- X LUSER *u;
- X{
- X SIGNED long weight, topweight;
- X struct pr *topweightpr;
- X register struct pr *pp; /* process pointer */
- X register PID_T curpid;
- X char **progs;
- X PID_T tpg; /* this tty's process group */
- X dev_t ttyd; /* tty device */
- X
- X# ifndef Umax
- X if( u->u_flags & U_BADTTY )
- X return( NULL );
- X
- X if( !initialized ) {
- X initialized = TRUE;
- X prvec = readpr(); /* read process table once. */
- X } /* not initialized */
- X
- X if( prvec == NULL ) /* have processes? */
- X return( NULL );
- X
- X if( ISBADFILE( kmem ) ) /* have kernel memory? */
- X return( NULL );
- X# endif /* Umax not defined */
- X
- X tpg = -1; /* terminal process group */
- X ttyd = u->u_ttydev; /* get terminal device number */
- X
- X topweight = MINUS_INF;
- X topweightpr = NULL;
- X
- X# ifdef sun
- X /*
- X * Sun console redirection (under SunOS 3.x and 4.0.3);
- X *
- X * values are major,minor
- X * consdev rconsdev
- X * When the console device is the screen/kbd: 0,0(*) 0,0(*)
- X * When the console is serial port n: 12,n 12,n
- X * When the console is redirected to ptyN: 20,N as above
- X *
- X * (*) under SunOS 4.0, 4.0.1 and 4.1 this is always 1,0
- X * but not under 4.0.3?!!
- X */
- X
- X# if SunOS >= 400 && SunOS != 403
- X if( ttyd == dev_console ) /* utter crockery */
- X ttyd = makedev(1,0); /* seems to work! */
- X# endif /* SunOS >= 400 && SunOS != 403 */
- X
- X if( ttyd == dev_console && /* this is /dev/console */
- X consdev == rconsdev ) /* check if boot physical console */
- X ttyd = consdev; /* is not screen, and not redirectd*/
- X# endif /* sun defined */
- X
- X
- X# ifdef Umax
- X ttyprocs( ttyd ); /* create array of processes on */
- X /* this terminal */
- X# endif /* Umax defined */
- X
- X# ifdef DEBUGSW
- X if( sw_debug )
- X printf("ttyd=%#x\n", ttyd );
- X# endif /* DEBUGSW defined */
- X
- X for( pp = prvec; pp->pr_stat != 0; pp++ ) { /* for all processes */
- X if(
- X# ifndef Umax
- X pp->pr_ttyp == NULL || /* no tty? */
- X# endif /* Umax not defined */
- X ttyd != pp->pr_ttyd ) /* tty mismatch? */
- X continue; /* yes, continue */
- X
- X# define ONE 8 /* do fixed point fractions */
- X weight = 0;
- X curpid = pp->pr_pid;
- X
- X if( tpg == -1 ) /* try to get terminal */
- X tpg = gettpg( pp, u ); /* process group */
- X
- X# ifdef Umax
- X switch( pp->pr_stat ) {
- X case SRUN:
- X if( pp->pr_wchan == 0 )
- X weight += ONE;
- X break;
- X case SWAIT:
- X weight += ONE; /* some semaphore */
- X break;
- X# ifndef SEVENT
- X# define SEVENT (SEXEC+1) /* in proc.h but not pmdefs.h */
- X# endif /* SEVENT not defined */
- X case SEVENT: /* some event wait.. */
- X weight += ONE / 2;
- X break;
- X } /* switch */
- X# else /* Umax not defined */
- X switch( waitstate( pp ) ) {
- X case WS_TI:
- X weight += ONE * 4;
- X break;
- X case WS_TO:
- X weight += ONE * 2;
- X break;
- X case WS_TW: /* random terminal wait */
- X case WS_SE: /* select */
- X weight += ONE / 2;
- X break;
- X case WS_RU: /* no wait */
- X if( pp->pr_stat == SRUN ) /* runnable? */
- X weight += ONE;
- X break;
- X default:
- X break;
- X } /* case */
- X# endif /* Umax not defined */
- X
- X/* sigh. give no special preference to leader (for things running under sh) */
- X/* if( curpid == tpg ) /* pid matches tty group? */
- X/* weight += ONE; /* leader */
- X
- X/* give bonus to children of leader? What about ..grandchildren? *WISH* */
- X/* (pp->pr_ppid == tpg ) */
- X/* other ways to benefit by looking up parents?? (done in getcommand()) */
- X
- X /* *WISH* perhaps consider p_pctcpu */
- X
- X if( pp->pr_pgrp == tpg ) /* process in process group? */
- X weight += ONE;
- X
- X if( pp->pr_stat == SSTOP ) /* stopped? */
- X weight -= ONE / 2;
- X
- X if( pp->pr_ppid == INIT_PID ) /* child of init? */
- X weight -= ONE / 2;
- X
- X if( pp->pr_pgrp == 0 ) /* no process group? */
- X weight -= ONE / 4;
- X
- X# ifdef SLOAD
- X if( (pp->pr_flag & SLOAD) == 0 ) /* swapped? */
- X weight -= ONE / 4;
- X# endif /* SLOAD defined */
- X
- X /* this is to catch programs started by sh with '&' */
- X if( pp->pr_intr == S_IGNORE && pp->pr_quit == S_IGNORE )
- X weight -= ONE / 4;
- X
- X if( pp->pr_hup == S_IGNORE ) /* process is nohup? */
- X weight -= ONE / 4; /* was once 1/8th */
- X
- X /*
- X * penalize ugly stuff like "gamescontrol" which
- X * tend to have high pids.
- X */
- X for( progs = hidden; *progs != NULL; progs++ )
- X if( strcmp( pp->pr_cmd, *progs ) == 0 ) {
- X weight -= ONE;
- X break;
- X }
- X
- X pp->pr_weight = weight = (weight<<PID_BITS)/ONE + curpid;
- X if( weight > topweight ) { /* beat previous winner */
- X topweight = weight;
- X topweightpr = pp;
- X } /* beat winner */
- X
- X# ifdef DEBUGSW
- X if( sw_debug )
- X dumppr( pp );
- X# endif /* DEBUGSW defined */
- X
- X } /* for pp */
- X
- X return( topweightpr );
- X} /* getcommand2 */
- X
- X# ifdef Umax
- XLOCAL ttyprocs( dev ) /* get pr's for this terminal */
- X dev_t dev;
- X{
- X struct stat_descr sd;
- X register int i;
- X register struct pr *pp;
- X register struct proc_detail *pd;
- X struct proc_detail dd[ MAXP ];
- X
- X sd.sd_next = NULL;
- X sd.sd_objid = dev;
- X sd.sd_subsys = SUBSYS_PROC;
- X sd.sd_type = PROCTYPE_DETAIL;
- X sd.sd_options = PROC_DETAIL_TERM | PROC_DETAIL_GLEADER;
- X sd.sd_addr = (char *) dd; /* point to data region */
- X sd.sd_size = sizeof( dd ); /* give size */
- X sd.sd_sizeused = 0;
- X
- X if( inq_stats(1, &sd) != 0 ) {
- X perror("inq_stats");
- X exit(1);
- X }
- X
- X# define SZ sizeof( struct proc_detail )
- X pp = prvec;
- X pd = dd;
- X for( i = sd.sd_sizeused; i >= SZ; i -= SZ ) {
- X pp->pr_pid = pd->pd_pid;
- X pp->pr_ppid = pd->pd_ppid;
- X pp->pr_pgrp = pd->pd_pgrp;
- X pp->pr_uid = pd->pd_uid;
- X pp->pr_flag = pd->pd_flag;
- X pp->pr_stat = pd->pd_state;
- X pp->pr_ttyd = dev;
- X strncpy(pp->pr_cmd, pd->pd_command, sizeof( pp->pr_cmd ) );
- X# define SIGFIG(pd,s) ( (pd->pd_sigignore & (1<<(s))) ? S_IGNORE : \
- X (pd->pd_sigcatch & (1<<(s))) ? S_CATCH : S_DEFAULT )
- X pp->pr_hup = SIGFIG(pd,SIGHUP);
- X pp->pr_intr = SIGFIG(pd,SIGINT);
- X pp->pr_quit = SIGFIG(pd,SIGQUIT);
- X# undef SIGFIG
- X pp->pr_wchan = (caddr_t) pd->pd_sem; /* why not? */
- X /* no way to figure out what */
- X /* EVENT is what tho... */
- X pd++;
- X pp++;
- X } /* while i */
- X pp->pr_stat = 0; /* mark end */
- X} /* ttyprocs */
- X# endif /* Umax defined */
- X
- XGLOBAL void
- Xdumppr( pp )
- X register struct pr *pp;
- X{
- X int st;
- X waitstate_t s;
- X
- X st = pp->pr_stat;
- X if( st < 0 || st > sizeof( procstates ) - 1 )
- X st = 0;
- X# ifdef Umax
- X s = WS_SL;
- X# else /* Umax not defined */
- X s = waitstate( pp );
- X# endif /* Umax not defined */
- X printf("%6dp %6dpp %6dpg %2s %2s %ci %cq %ch %5du %#8x %s %s %d\n",
- X pp->pr_pid,
- X pp->pr_ppid,
- X pp->pr_pgrp,
- X procstates[ st ],
- X# if defined(SLOAD) && !defined(UmaxV)
- X ( (pp->pr_flag & SLOAD) ? "" : "SW" ),
- X# else /* not defined(SLOAD) && !defined(UmaxV) */
- X "",
- X# endif /* not defined(SLOAD) && !defined(UmaxV) */
- X SIGNAME[ (int) pp->pr_intr ],
- X SIGNAME[ (int) pp->pr_quit ],
- X SIGNAME[ (int) pp->pr_hup ],
- X pp->pr_uid,
- X pp->pr_ttyd,
- X# if Umax == 42
- X "", /* always bogus */
- X# else /* not Umax == 42 */
- X WAITSTATENAME[ (int)s ],
- X# endif /* not Umax == 42 */
- X pp->pr_cmd,
- X pp->pr_weight
- X );
- X} /* dumppr */
- X
- XGLOBAL int gettpg( pp, u )
- Xregister struct pr *pp;
- XLUSER *u;
- X{
- X short tpg; /* MUST BE SHORT! (for SHORT_TTYP) */
- X# ifdef Umax
- X static int checked = FALSE, notty = FALSE;
- X int f, w;
- X char devn[ 30 ];
- X
- X /* inq_stats does has no way to get terminal process group. Newer
- X * releases have /dev/kmem, but rather than have to deal with kmem
- X * at all we open the tty (for write!) and do the ioctl! if users
- X * do "mesg n" finger has to run suid root to ensure access (it is
- X * safe to do so)! (see BUGS in man page)
- X */
- X strcpy( devn, "/dev/" );
- X strcat( devn, u->u_line );
- X
- X if( !checked ) { /* check if we have a tty */
- X if( (f = open( "/dev/tty", 1)) >= 0 )
- X close( f ); /* yes we do */
- X else
- X notty = TRUE; /* we don't */
- X checked = TRUE;
- X }
- X
- X tpg = -2;
- X if( (f = open( devn, 1 )) >= 0 ) { /* open for write!! */
- X if( ioctl( f, TIOCGPGRP, &w ) == 0 ) /* to get pgrp!!! */
- X tpg = w;
- X close( f );
- X
- X /* flush tty association -- so fingerd doesn't get attached!! */
- X if( notty && (f = open( "/dev/tty", 1)) >= 0 ) { /* if no tty */
- X ioctl( f, TIOCNOTTY, 0 ); /* flush assoc with one */
- X close( f ); /* we just opened */
- X }
- X }
- X# else /* Umax not defined */
- X# ifndef AIX3
- X# ifdef SHORT_TTYP
- X /* ttyp is pointer to (short) process group in stream structure! */
- X if( ! KMEMREAD( (long)pp->pr_ttyp, (char *)&tpg, sizeof(tpg)) )
- X tpg = -2;
- X# else /* SHORT_TTYP not defined */
- X /* read just process group from tty struct */
- X if( ! KMEMREAD( (long)&pp->pr_ttyp->t_pgrp, (char *)&tpg, sizeof(tpg)) )
- X tpg = -2;
- X# endif /* SHORT_TTYP not defined */
- X# endif /* AIX3 not defined */
- X# endif /* Umax not defined */
- X# ifdef DEBUGSW
- X if( sw_debug )
- X printf("tpg=%d\n", tpg );
- X# endif /* DEBUGSW defined */
- X return( tpg );
- X} /* gettpg */
- X
- XGLOBAL void
- Xgetstate( bp, pp )
- X char *bp;
- X struct pr *pp;
- X{
- X waitstate_t s;
- X int st;
- X
- X st = pp->pr_stat;
- X if( st < 0 || st > sizeof( procstates ) - 1 )
- X st = 0;
- X
- X# ifdef Umax
- X# if Umax == 42
- X bp[0] = procstates[st][0];
- X bp[1] = procstates[st][1];
- X bp[2] = procstates[st][2];
- X bp[3] = procstates[st][3];
- X# endif /* Umax == 42 */
- X# else /* Umax not defined */
- X if( st == SSLEEP ) {
- X s = waitstate( pp );
- X bp[0] = WAITSTATENAME[ (int)s ][0];
- X bp[1] = WAITSTATENAME[ (int)s ][1];
- X }
- X else {
- X bp[0] = procstates[st][0];
- X bp[1] = procstates[st][1];
- X }
- X
- X bp[2] = bp[3] = ' ';
- X# if defined(SLOAD) && !defined(UmaxV)
- X if( (pp->pr_flag & SLOAD) == 0 ) {
- X bp[2] = 'S';
- X bp[3] = 'W';
- X }
- X# endif /* defined(SLOAD) && !defined(UmaxV) */
- X# endif /* Umax not defined */
- X bp[4] = EOS;
- X
- X} /* getstate */
- X
- X/*
- X * Local variables:
- X * comment-column: 40
- X * End:
- X */
- END_OF_getcommand.c
- if test 14997 -ne `wc -c <getcommand.c`; then
- echo shar: \"getcommand.c\" unpacked with wrong size!
- fi
- # end of overwriting check
- fi
- echo shar: End of archive 6 \(of 7\).
- cp /dev/null ark6isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 7 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-
-